package utils

import (
	"sort"
)

/*
1.将切片 b 的元素追加到切片 a 之后：a = append(a, b...)

2.复制切片 a 的元素到新的切片 b 上：

  b = make([]T, len(a))
  copy(b, a)

3.删除位于索引 i 的元素：a = append(a[:i], a[i+1:]...)

4.切除切片 a 中从索引 i 至 j 位置的元素：a = append(a[:i], a[j:]...)

5.为切片 a 扩展 j 个元素长度：a = append(a, make([]T, j)...)

6.在索引 i 的位置插入元素 x：a = append(a[:i], append([]T{x}, a[i:]...)...)

7.在索引 i 的位置插入长度为 j 的新切片：a = append(a[:i], append(make([]T, j), a[i:]...)...)

8.在索引 i 的位置插入切片 b 的所有元素：a = append(a[:i], append(b, a[i:]...)...)

9.取出位于切片 a 最末尾的元素 x：x, a = a[len(a)-1], a[:len(a)-1]

*/

type TCompareLessFunc func(c1, c2 interface{}) bool

type ArrayList struct {
	lst []interface{}
}

func NewArrayList(intialCap int) *ArrayList {
	rval := &ArrayList{lst: make([]interface{}, 0, intialCap)}
	return rval
}

func (this *ArrayList) Insert(idx int, val interface{}) {
	this.lst = append(this.lst[:idx], append([]interface{}{val}, this.lst[idx:]...)...)
}

func (this *ArrayList) CheckInsert(idx int, val interface{}) {
	if idx < 0 {
		idx = 0
	} else if idx > len(this.lst) {
		idx = len(this.lst)
	}
	this.Insert(idx, val)
}

func (this *ArrayList) List() []interface{} {
	return this.lst
}

func (this *ArrayList) Append(val interface{}) {
	this.lst = append(this.lst, val)
}

func (this *ArrayList) AppendList(lst ...interface{}) {
	this.lst = append(this.lst, lst...)
}

func (this *ArrayList) Delete(idx int) {
	this.lst = append(this.lst[:idx], this.lst[idx+1:]...)
}

func (this *ArrayList) CheckDelete(idx int) {
	if idx < 0 {
		idx = 0
	} else if idx >= len(this.lst) {
		idx = len(this.lst) - 1
	}
	this.Delete(idx)
}

func (this *ArrayList) DeleteRange(start, end int) {
	this.lst = append(this.lst[:start], this.lst[end:]...)
}

func (this *ArrayList) InsertList(idx int, lst []interface{}) {
	//a = append(a[:i], append(b, a[i:]...)...)
	this.lst = append(this.lst[:idx], append(lst, this.lst[idx:]...)...)
}

func (this *ArrayList) InsertArrayList(idx int, arr *ArrayList) {
	this.InsertList(idx, arr.lst)
}

func (this *ArrayList) Count() int {
	return len(this.lst)
}

func (this *ArrayList) Range(cb func(val interface{}) bool) {
	for i := 0; i < len(this.lst); i++ {
		if !cb(this.lst[i]) {
			break
		}
	}
}

func (this *ArrayList) PopHead() (ok bool, val interface{}) {
	l := len(this.lst)
	if l == 0 {
		return false, nil
	}
	val, this.lst = this.lst[0], this.lst[1:]
	return true, val
}

/*
**

	对返回的lst进行操作(排序,插入等其他修改)会影响内部list
*/
func (this *ArrayList) PopHeadMax(max int) []interface{} {
	l := len(this.lst)
	if l == 0 {
		return nil
	}
	if l > max {
		l = max
	}
	rval := this.lst[:l]
	this.lst = this.lst[l:]
	return rval
}

/*
**

	对返回的lst进行操作(排序,插入等其他修改)不会影响内部list
*/
func (this *ArrayList) PopHeadMaxCopy(max int) []interface{} {
	l := len(this.lst)
	if l == 0 {
		return nil
	}
	if l > max {
		l = max
	}
	rval := make([]interface{}, 0, l)
	rval = append(rval, this.lst[:l]...)
	this.lst = this.lst[l:]
	return rval
}

func (this *ArrayList) PopTail() (ok bool, val interface{}) {
	l := len(this.lst)
	if l == 0 {
		return false, nil
	}
	val, this.lst = this.lst[l-1], this.lst[:l-1]
	return true, val
}

func (this *ArrayList) Sort() {
	sort.Slice(this.lst, func(i, j int) bool {
		return CompareLess(this.lst[i], this.lst[j])
	})
}

func (this *ArrayList) SortDesc() {
	sort.Slice(this.lst, func(i, j int) bool {
		return !CompareLess(this.lst[i], this.lst[j])
	})
}

func (this *ArrayList) SortCustom(lessfunc TCompareLessFunc) {
	sort.Slice(this.lst, func(i, j int) bool {
		return lessfunc(this.lst[i], this.lst[j])
	})
}

type ArraySortedList struct {
	lst    []interface{}
	lessfn TCompareLessFunc
}

func NewArraySortedList(intialCap int) *ArraySortedList {
	rval := &ArraySortedList{lst: make([]interface{}, 0, intialCap)}
	return rval
}

func (this *ArraySortedList) SetCompareFunc(fn TCompareLessFunc) {
	this.lessfn = fn
}

func (this *ArraySortedList) Insert(val interface{}) {
	if this.lessfn == nil {
		this.lessfn = CompareLess
	}

	n := len(this.lst)

	idx := sort.Search(n, func(i int) bool {
		return this.lessfn(val, this.lst[i])
	})
	if idx == n {
		this.lst = append(this.lst, val)
		return
	}

	this.lst = append(this.lst, nil)       // try to grow the slice in place, any entry works.
	copy(this.lst[idx+1:], this.lst[idx:]) // Move shorter entries down
	this.lst[idx] = val
}

func (this *ArraySortedList) PopTail() (ok bool, val interface{}) {
	l := len(this.lst)
	if l == 0 {
		return false, nil
	}
	val, this.lst = this.lst[l-1], this.lst[:l-1]
	return true, val
}

func (this *ArraySortedList) PopHead() (ok bool, val interface{}) {
	l := len(this.lst)
	if l == 0 {
		return false, nil
	}
	val, this.lst = this.lst[0], this.lst[1:]
	return true, val
}

func (this *ArraySortedList) Head() (val interface{}) {
	return this.lst[0]
}

func (this *ArraySortedList) Tail() (val interface{}) {
	return this.lst[len(this.lst)-1]
}
